package dmmm.assembler;

import java.util.ArrayList;

public class Disassembler {
	
	private boolean ok=true;
	private String decodedInstr;

	

	private static String[][] instructions = {
		{"nop",		"halt",  	null,   	null,    	"intd",  	"inte",   	null,    	null},
		{null,		"jmp",   	"jsr",  	"rts",   	"int",   	"rti",    	null,    	null},
		{"beql",	"bneql", 	"bneg", 	"bnneg", 	"bovf",  	"bnovf",  	"bcar",  	"bncar"},
		{"bgrt",	"bgrte", 	"blss", 	"blsse", 	"bgrtu", 	"bgrteu",	"blssu", 	"blsseu"},
		{"ldb",		"ldw",   	"stb",  	"stw",   	"popb", 	"popw",   	"pushb", 	"pushw"},
		{"ldivtp",	"stivtp",	"ldimr", 	"stimr", 	"ldsp", 	"stsp", 	null,   	null},
		{"add",		"sub", 		"inc", 		"dec", 		"and",		"or",		"xor",		"not"},
		{"asr",		"lsr",		"ror",		"rorc",		"asl",		"lsl",		"rol",		"rolc"}
		};
	
	public Disassembler(ArrayList<Integer> code) {
		ok=true;
		for (int i = 0; i < code.size(); ) {
			if(i==code.size()){
				ok=false;
				break;
			}
			int ins = code.get(i++);
			int group = (ins & 0x38)>>3;
			int opcode = ins & 0x7;
			decodedInstr=""+instructions[group][opcode]+" ";
			
			if (group == 0
				|| group == 1 && (opcode == 3 || opcode == 5)
				|| group == 4 && (opcode >= 4 && opcode <= 7)
				|| group == 5
				|| group == 6 && (opcode == 2 || opcode == 3 || opcode == 7)
				|| group == 7) {
					
				//System.out.println();	
			}
			
			if (group == 2 || group == 3 || (group == 1 && opcode == 4)) {
				if(i==code.size()){
					ok=false;
					break;
				}
				decodedInstr=decodedInstr+code.get(i++);
			}
			
			if (group == 1 && (opcode == 1 || opcode == 2)) {
				if(i==code.size()){
					ok=false;
					break;
				}
				int disp = (code.get(i++) << 8);
				if(i==code.size()){
					ok=false;
					break;
				}
				disp |=code.get(i++);
				decodedInstr=decodedInstr+(disp);
			}
			
			if (group == 4 && (opcode >= 0 && opcode <= 3)
				|| group == 6 && (opcode != 2 && opcode != 3 && opcode != 7)) {
				if(i==code.size()){
					ok=false;
					break;
				}
				int secondByte = code.get(i++);
				int typeOfAddressing = (secondByte & 0xE0) >> 5;
				int register = secondByte & 0x1F;
				
				if (typeOfAddressing == 0) {
					
					decodedInstr=decodedInstr+("r"+register);
					
				} else if (typeOfAddressing == 1) {
					
					decodedInstr=decodedInstr+("(r"+register+")");
					
				} else if (typeOfAddressing == 2) {
					if(i==code.size()){
						ok=false;
						break;
					}
					int mem = (code.get(i++) << 8);
					if(i==code.size()){
						ok=false;
						break;
					}
					mem |= code.get(i++);
					decodedInstr=decodedInstr+(mem);
					
				} else if (typeOfAddressing == 3) {
					if(i==code.size()){
						ok=false;
						break;
					}
					int mem = (code.get(i++) << 8);
					if(i==code.size()){
						ok=false;
						break;
					}
					mem |= code.get(i++);
					decodedInstr=decodedInstr+("("+mem+")");
					
				} else if (typeOfAddressing == 4) {
					if(i==code.size()){
						ok=false;
						break;
					}
					int disp = (code.get(i++) << 8);
					if(i==code.size()){
						ok=false;
						break;
					}
					disp |= code.get(i++);
					decodedInstr=decodedInstr+("(r"+register+")"+disp);
					
				} else if (typeOfAddressing == 5) {
					if(i==code.size()){
						ok=false;
						break;
					}
					int disp = (code.get(i++) << 8);
					if(i==code.size()){
						ok=false;
						break;
					}
					disp |= code.get(i++);
					decodedInstr=decodedInstr+("[r"+register+"]"+disp);
					
				} else if (typeOfAddressing == 6) {
					if(i==code.size()){
						ok=false;
						break;
					}
					int disp = (code.get(i++) << 8);
					if(i==code.size()){
						ok=false;
						break;
					}
					disp |=code.get(i++);
					decodedInstr=decodedInstr+("(pc)"+disp);
					
				} else if (typeOfAddressing == 7) {
					
					int disp;
					if (group == 4 && opcode == 1) {
						if(i==code.size()){
							ok=false;
							break;
						}
						disp = (code.get(i++) << 8);
						if(i==code.size()){
							ok=false;
							break;
						}
						disp |=code.get(i++);
					} else {
						if(i==code.size()){
							ok=false;
							break;
						}
						disp = code.get(i++);
					}
					decodedInstr=decodedInstr+("#"+disp);
				}
			}
		System.out.println(decodedInstr);
		}
	}
	public boolean isOk() {
		return ok;
	}

	public void setOk(boolean ok) {
		this.ok = ok;
	}
	public String getDecodedInstr() {
		return decodedInstr;
	}
	public void setDecodedInstr(String decodedInstr) {
		this.decodedInstr = decodedInstr;
	}
}
